package gu.sql2java;

import java.util.Map;
import com.google.common.base.Predicate;

/**
 * general operation definition for accessing a record from database  
 * @author guyadong
 *
 */
public interface BaseBean{
    /**
     * Determines if the current object is new.
     *
     * @return true if the current object is new, false if the object is not new
     */
    public boolean isNew();
    
    /**
	 * Specifies to the object if it has been set as new.
	 *
	 * @param isNew the boolean value to be assigned to the isNew field
	 */
	public void setNew(boolean isNew);

	/**
     * @return the initialized status of columns
     */
    public int getInitialized();

    /**
     * @param initialized the initialized status of columns 
     */
    public void setInitialized(int initialized);
    
    /**
     * @return the modified status of columns
     */
    public int getModified();
    
    /**
     * @param modified the modified status of columns
     */
    public void setModified(int modified);
    
    /**
     * Determines if the object has been modified since the last time this method was called.<br>
     * We can also determine if this object has ever been modified since its creation.
     *
     * @return true if the object has been modified, false if the object has not been modified
     */
    public boolean beModified();
    
    /**
     * set the object modification status to 'modified' and initialization status to 'initialized'
	 * @param columnID
	 * @since 3.21.0
	 */
	public void modified(int... columnIDs);

	/**
     * Resets the object modification status to 'not modified'.
     */
    public void resetIsModified();
    /**
     * reset columns modification status defined by {@code mask} 
     * @param mask
     */
	void resetModified(int mask);
    /**
     * Resets the primary keys modification status to 'not modified'.
     */
    public void resetPrimaryKeysModified();
    /**
     * Determines if the {@code columnID} has been initialized.<br>
     * It is useful to determine if a field is null on purpose or just because it has not been initialized.
     * @param columnID column id
     * @return true if the field has been initialized, false otherwise
     */
    public boolean isInitialized(int columnID);
    /**
     * Determines if the {@code columnID} has been modified.
     * @param columnID column id
     * @return true if the field has been modified, false if the field has not been modified
     */
    public boolean isModified(int columnID);
    /**
     * Determines if the {@code columnIDs} has been modified.
     * @param columnIDs column id array
     * @return true if  any field has been modified, otherwise false
     * @since 3.25.0
     */
    public boolean isModified(int... columnIDs);
    /**
     * Determines if the {@code columns} has been modified.
     * @param columns column name array
     * @return true if any field has been modified, , otherwise false
     * @since 3.25.0
     */
    public boolean isModified(String... columns);
    /**
     * Determines if the {@code column} has been initialized.<br>
     * It is useful to determine if a field is null on purpose or just because it has not been initialized.
     * @param column column name
     * @return true if the field has been initialized, false otherwise
     */
    public boolean isInitialized(String column);
    /**
     * Determines if the {@code column} has been modified.
     * @param column column name
     * @return true if the field has been modified, false if the field has not been modified
     */
    public boolean isModified(String column);
    /**
     * Determines if the {@code nestedName} has been modified.
     * @param nestedName nest name start with [tablename.]column name, splitted with '.'
     * @return true if the field has been modified, false if the field has not been modified
     * @since 3.15.0
     */
    public boolean isModifiedNested(String nestedName);

    /**
     * @return modified column id list or empyt array if none column be modified
     * @since 3.15.0
     */
    public int[] modifiedColumnIDs();

    /**
     * @return modified column name list or empyt array if none column be modified
     * @since 3.15.0
     */
    public String[] modifiedColumns();

    /**
     * @return modified column count
     * @since 3.15.0
     */
    public int modifiedColumnCount();

	/**
     * Copies the passed bean into the current bean.
     *
     * @param bean the bean to copy into the current bean
     * @return this bean
     */
    public <B extends BaseBean> B copy(B bean);
    /**
     * Copies the passed bean into the current bean.
     *
     * @param bean the bean to copy into the current bean
     * @param fieldList the column id list to copy into the current bean,if null or empty,copy all fields
     * @return always this bean
     */
    public <B extends BaseBean> B copy(B bean, int... fieldList);
    /**
     * Copies the passed bean into the current bean.
     *
     * @param bean the bean to copy into the current bean
     * @param fieldList the column name list to copy into the current bean
     * @return always this bean
     */
    public <B extends BaseBean> B copy(B bean, String... fieldList);
    /**
     * Copies the passed bean into the current bean.
     *
     * @param bean the bean to copy into the current bean
     * @param fieldFilter the filter for column name,ignore if null
     * @param fieldList the column id list to copy into the current bean
     * @return always this bean
     * @since 3.15.0
     */
    public <B extends BaseBean> B copy(B bean, Predicate<Integer> fieldFilter, int... fieldList);

	/**
     * Copies the passed bean into the current bean.
     *
     * @param bean the bean to copy into the current bean
     * @param fieldFilter the filter for column name,ignore if null
     * @param fieldList the column name list to copy into the current bean
     * @return always this bean
     * @since 3.14.0
     */
    <B extends BaseBean> B copy(B bean, Predicate<String> fieldFilter, String... fieldList);

    /**
     * Copies the passed F bean into the current bean.
     * @param <B> from bean type
     * @param <F> this bean type
     * @param from
     * @param columnsMap columns map from F to B 
     * @return always this bean
     */
    <B extends BaseBean, F extends BaseBean> B copy(F from, Map<Integer,Integer> columnsMap);
    
    /**
     * Copies the passed values into the current bean.
     * @param values
     * @return always this bean
     */
    public <B extends BaseBean> B copy(Map<Integer, Object>values);
    /**
     * check columns equation. 
     *
     * @param object the bean to compare
     * @param fieldFilter the filter for column name,ignore if null
     * @param fieldList the column name list to compare to the current bean
     * @return {@code true} if special columns is all equal  to object,otherwise false
     * @since 3.15.0
     */
    public boolean equalColumn(Object object, Predicate<String> fieldFilter, String... fieldList);
    /**
     * check columns equation. 
     *
     * @param object the bean to compare
     * @param fieldFilter the filter for column name,ignore if null
     * @param fieldList the column id list to compare to the current bean
     * @return {@code true} if special columns is all equal  to object,otherwise false
     * @since 3.15.0
     */
	public boolean equalColumn(Object object, Predicate<Integer> fieldFilter, int... fieldList);
    /**
     * check columns equation. 
     *
     * @param object the bean to compare
     * @param fieldList the column id list to compare to the current bean
     * @return {@code true} if special columns is all equal  to object,otherwise false
     * @since 3.15.0
     */
    public boolean equalColumn(Object object, int... fieldList);
    /**
     * check column equation. 
     *
     * @param object the bean to compare
     * @param fieldList the column id to compare to the current bean
     * @return {@code true} if special column is equal  to object,otherwise false
     * @since 3.15.0
     */
    public boolean equalColumn(Object object, int columnId);


    /**
     * 
     * @param columnID column id
     * @return return a object representation of the given column id
     */
    public <T> T getValue(int columnID);
    
    /**
     * 
     * @param columnID column id
     * @return return a origin object representation of the given column id
     * @since 3.18.0
     */
    public <T> T getOriginValue(int columnID);
    /**
     * @param columnID
     * @return return a value as JDBC store type representation of the given column id
     * @since 3.22.0
     */
    public <T> T getJdbcValue(int columnID);

	/**
     * set a value representation of the given column id
     * @param columnID column id
     * @param value
     */
    public <T> void setValue(int columnID,T value);
    /**
     * set a value representation of the given column id if value is not null
     * @param columnID column id
     * @param value
     * @return true if not null,otherwise false
     * @since 3.14.0
     */
    public <T> boolean setValueIfNonNull(int columnID,T value);
    /**
     * set a value representation of the given column id if value is not equal with old
     * @param columnID column id
     * @param value
     * @return true if not equal,otherwise false
     * @since 3.14.0
     */
    public <T> boolean setValueIfNonEqual(int columnID, T value);
    /**
     * set a value representation of the given column id if expression is true
     * @param columnID column id
     * @param value
     * @return expression always
     * @since 3.14.0
     */
    public <T> boolean setValueIf(boolean expression, int columnID, T value);

    /**
     * 
     * @param column column name
     * @return return a object representation of the given field
     */
    public <T> T getValue(String column);
    /**
     * 
     * @param columnID column id
     * @return return a object representation of the given column id or throw {@link NullPointerException} if value is null
     */
    public <T> T getValueChecked(int columnID);
    /**
     * 
     * @param column column name
     * @return return a object representation of the given field or throw {@link NullPointerException} if value is null
     */
    public <T> T getValueChecked(String column);
    /**
     * set a value representation of the given field
     * @param column column name
     * @param value
     */
    public void setValue(String column,Object value);
    
    /**
     * set a value representation of the given field if value is not null
     * @param column column name
     * @param value
     * @return true if not null,otherwise false
     * @since 3.14.0
     */
    public boolean setValueIfNonNull(String column, Object value);
    /**
     * set a value representation of the given field if value is not equal with old
     * @param column column name
     * @param value
     * @return true if not equal,otherwise false
     * @since 3.14.0
     */
    public boolean setValueIfNonEqual(String column, Object value);

    /**
     * set a value representation of the given field if expression is true
     * @param column column name
     * @param value
     * @return expression always
     * @since 3.14.0
     */
    public boolean setValueIf(boolean expression, String column, Object value);

    /**
     * @param columnIds column id that will be output, if null or empty,output all columns
     * @return values array for all fields
     */
    public Object[] asValueArray(int...columnIds);
    /**
	 * @return view of values map for all fields, column name -- value
	 */
	public Map<String, Object> asNameValueMap();
	
	/**
	 * @param ignoreNull remove all null column
	 * @param ignoreColumns remove column name list
	 * @return values map for all fields, column name -- value
	 */
	public Map<String, Object> asNameValueMap(boolean ignoreNull,String ...ignoreColumns);
	/**
	 * @param ignoreNull remove all null column
	 * @param ignoreColumns remove column name list
	 * @return values map for all fields, column name -- value
	 */
	public Map<String, Object> asNameValueMap(boolean ignoreNull,Iterable<String>ignoreColumns);
	/**
	 * @param ignoreNull remove all null column
	 * @param include if {@code true},the {@code columns} is white list(include) for column, only output columns which in list,otherwise it's black list(exclude)
	 * @param columns column name list for white/black(include/exclude) list
	 * @return values map for all fields, column name -- value
	 */
    Map<String, Object> asNameValueMap(boolean ignoreNull, final boolean include, Iterable<String>columns);

    /**
     * @param ignoreNull remove all null column
	 * @param include if {@code true},the {@code columns} is white list(include) for column, only output columns which in list,otherwise it's black list(exclude)
     * @param columns remove column name list
     * @return values map for all fields, column name -- value
     */
	Map<String, Object> asNameValueMap(boolean ignoreNull, boolean include, String ...includeColumns);

	/**
     * @return values array for all primary key, empty array if no primary key
     */
    public Object[] primaryValues();
    /**
     * @param <T> PK type
     * @return value for primary key, throw {@link UnsupportedOperationException} if there is more than one primary key
     */
    public <T> T primaryValue();
   
    /**
     * @return table name of this bean
     */
    public String tableName();

	/**
     * @param notNull output not null field only if {@code true}
     * @param fullIfStringOrBytes for string or bytes field,output full content if {@code true},otherwise output length.
     * @return Returns a string representation of the object
     */
    public String toString(boolean notNull, boolean fullIfStringOrBytes);
    
    public BaseBean clone();
}
